package com.societyGames.system
{
import flash.utils.ByteArray;
import flash.utils.Dictionary;

public class FileCache
{
  private var _files:Dictionary = new Dictionary(); //string, ByteArray
  private var _pendingFiles:Dictionary = new Dictionary(); //string, PendingFile

  public function FileCache()
  {
  }

  /**
   * Load a url or use a cached value.
   * @param url The url of the file to load.
   * @param callback function(string, ByteArray):void
   **/
  public function load(url:String, callback:Function /*function(url:String, file:ByteArray):void*/, errorCallback:Function = null /*function(url:String):void*/):void
  {
    var byteArray:ByteArray = this._files[url];
    if (byteArray != null)
    {
      callback(url, byteArray);
    }
    else
    {
      var pendingFile:PendingFile = this._pendingFiles[url];
      if (pendingFile == null)
      {
        pendingFile = new PendingFile(url);
        pendingFile.addCallback(onFileLoaded);
      }
      pendingFile.addCallback(callback, errorCallback);
    }
  }

  public function removeCallback(url:String, callback:Function, errorCallback:Function = null):void
  {
    var pendingFile:PendingFile = this._pendingFiles[url];
    if (pendingFile != null)
    {
      pendingFile.removeCallback(callback, errorCallback);
    }
  }

  private function onFileLoaded(url:String, byteArray:ByteArray):void
  {
    delete this._pendingFiles[url];
    this._files[url] = byteArray;
  }
}
}

import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.utils.ByteArray;

class PendingFile extends EventDispatcher
{
  private var _url:String;
  private var _urlLoader:URLLoader;
  private var _callbacks:Array = []; //function(url:String, fileByteArray:ByteArray):void
  private var _errorCallbacks:Array = []; //function(url:String):void

  public function PendingFile(url:String)
  {
    this._url = url;
    this._urlLoader = new URLLoader();
    this._urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
    this._urlLoader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
    this._urlLoader.addEventListener(Event.COMPLETE, completeHandler);
    this._urlLoader.load(new URLRequest(url));
  }

  public function addCallback(callback:Function /*function(string, ByteArray):void*/, errorCallback:Function = null /*function(url:String):void*/):void
  {
    this._callbacks.push(callback);
    if (errorCallback != null)
    {
      this._errorCallbacks.push(errorCallback);
    }
  }

  public function removeCallback(callback:Function /*function(string, ByteArray):void*/, errorCallback:Function = null /*function(url:String):void*/):void
  {
    var index:int = this._callbacks.indexOf(callback);
    if (index != -1)
    {
      this._callbacks.splice(index, 1);
    }
    if (errorCallback != null)
    {
      index = this._errorCallbacks.indexOf(errorCallback);
      if (index != -1)
      {
        this._errorCallbacks.splice(index, 1);
      }
    }
  }

  private function completeHandler(event:Event):void
  {
    this._urlLoader.removeEventListener(Event.COMPLETE, completeHandler);
    this._urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
    var byteArray:ByteArray = ByteArray(this._urlLoader.data);
    for each (var callback:Function in this._callbacks)
    {
      callback(this._url, byteArray);
    }
  }

  private function errorHandler(e:IOErrorEvent):void
  {
    this._urlLoader.removeEventListener(Event.COMPLETE, completeHandler);
    this._urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
    for each (var errorCallback:Function in this._errorCallbacks)
    {
      errorCallback(this._url);
    }
    //throw new Error("Could not load file: " + this._url);
  }
}